import sys
!{sys.executable} -m pip install OWSLib==0.28.1
import owslib
from owslib.wfs import WebFeatureService
from owslib.ogcapi.features import Features
import geopandas as gpd
from datetime import datetime, timedeltaLook at the data that is availible through the Web Feature Service (WFS)
The datasets that are distributed throught the WFS are organized into collections. We can display the collections with the command:
w = Features(url = "https://pzh7fedpc0.execute-api.us-west-2.amazonaws.com") # Load base url of WFS
feature_collections = w.feature_collections()
feature_collections['public.eis_fire_fireline',
'public.eis_fire_newfirepix',
'public.eis_fire_newfirepix_2',
'public.eis_fire_perimeter',
'public.st_hexagongrid',
'public.st_squaregrid',
'public.st_subdivide']
We will focus on the public.eis_fire_fireline collection and the public.eis_fire_perimeter collection.
Learn about the public.eis_fire_perimeter collection
We can access information thaat drescribes the public.eis_fire_perimeter.
perm = w.collection('public.eis_fire_perimeter')
print("Spatial extent: ", perm['extent']['spatial']['bbox']) # Coordinates of the spatial extent
print("Coordinate Reference System: ", perm['extent']['spatial']['crs'])
print("Time range:", perm['extent']['temporal']['interval']) # Range of datetimes availibleSpatial extent: [[-123.99217987060547, 31.054306030273438, -101.49222564697266, 49.461177825927734]]
Coordinate Reference System: http://www.opengis.net/def/crs/EPSG/0/4326
Time range: [['2019-05-01T00:00:00+00:00', '2020-10-31T12:00:00+00:00']]
perm_q = w.collection_queryables('public.eis_fire_perimeter')
perm_cols = perm_q['properties']
perm_cols # Get perimeter columns and column types{'wkb_geometry': {'$ref': 'https://geojson.org/schema/Geometry.json'},
'meanfrp': {'name': 'meanfrp', 'type': 'number'},
't': {'name': 't', 'type': 'string'},
'fid': {'name': 'fid', 'type': 'number'},
'pixden': {'name': 'pixden', 'type': 'number'},
'duration': {'name': 'duration', 'type': 'number'},
'flinelen': {'name': 'flinelen', 'type': 'number'},
'fperim': {'name': 'fperim', 'type': 'number'},
'farea': {'name': 'farea', 'type': 'number'},
'n_newpixels': {'name': 'n_newpixels', 'type': 'number'},
'n_pixels': {'name': 'n_pixels', 'type': 'number'},
'ogc_fid': {'name': 'ogc_fid', 'type': 'number'}}
Contruct and API Query Read-in the Data
We will read the data into this notebook in two steps.
Construct a url that points to the subset of the data we are interested in
Read the data into a geopandas dataframe
To construct the url with pre-filtered data, we are using the owslib package. In the below example, we are reading in the public.eis_fire_perimetercollection , subsetting it by space using the bbox parameter, and subsetting it by time using the datetime.
The limit parameter desginated the maximum number of objects the query will return. The default limit is 10, so if we want to all of the fire perimeters within certain conditions, we need to make sure that the limit is large, and that the numberMatched is less than the limit.
The filter parameter lets us filter by the columns in the ‘public.eis_fire_perimeter’. Here we are filter for fires over 5km^2 and over 20 days long. filter supports SQL-style queries.
perm_results = w.collection_items(
'public.eis_fire_perimeter', # Name of the dataset we want
bbox=['-119.5', '36.8', '-118.9', '37.7'], # Coodrinates of bounding box,
datetime=['2020-01-01T00:00:00+00:00/2020-10-31T12:00:00+00:00'], # Date range
limit=1000,
filter="farea>5 AND duration>20"
)
print(perm_results['numberMatched']) # Less than the limit
perm_results['links'][1]['href'] # The url query we constucted125
'https://pzh7fedpc0.execute-api.us-west-2.amazonaws.com/collections/public.eis_fire_perimeter/items?bbox=-119.5%2C36.8%2C-118.9%2C37.7&datetime=2020-01-01T00%3A00%3A00%2B00%3A00%2F2020-10-31T12%3A00%3A00%2B00%3A00&limit=1000&filter=farea%3E5+AND+duration%3E20'
## Read in the filtered data to a GeoPandas DataFrame
df = gpd.GeoDataFrame.from_features(perm_results["features"])
df| geometry | meanfrp | t | fid | pixden | duration | flinelen | fperim | farea | n_newpixels | n_pixels | ogc_fid | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | POLYGON ((-118.98956 37.14274, -118.98955 37.1... | 0.000000 | 2020-10-24T00:00:00 | 6683 | 32.483377 | 30.5 | 0.000000 | 11.731364 | 7.326824 | 0 | 238 | 39758 |
| 1 | POLYGON ((-118.98956 37.14274, -118.98955 37.1... | 0.000000 | 2020-10-25T00:00:00 | 6683 | 32.483377 | 30.5 | 0.000000 | 11.731364 | 7.326824 | 0 | 238 | 39759 |
| 2 | POLYGON ((-118.98956 37.14274, -118.98956 37.1... | 0.000000 | 2020-10-08T12:00:00 | 6683 | 32.346892 | 29.5 | 0.000000 | 11.731364 | 7.326824 | 0 | 237 | 39760 |
| 3 | POLYGON ((-118.98956 37.14274, -118.98956 37.1... | 0.000000 | 2020-10-06T00:00:00 | 6683 | 32.210409 | 26.5 | 0.000000 | 11.731358 | 7.326824 | 0 | 236 | 39761 |
| 4 | POLYGON ((-118.98956 37.14273, -118.98956 37.1... | 0.580000 | 2020-10-03T00:00:00 | 6683 | 32.333326 | 24.5 | 0.000000 | 11.731136 | 7.268043 | 1 | 235 | 39762 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 120 | POLYGON ((-119.43342 37.31364, -119.43343 37.3... | 24.795108 | 2020-10-02T12:00:00 | 6280 | 19.811109 | 27.5 | 23.845096 | 270.752955 | 1453.780326 | 139 | 28801 | 40607 |
| 121 | POLYGON ((-119.43342 37.31364, -119.43342 37.3... | 2.427910 | 2020-10-02T00:00:00 | 6280 | 19.742769 | 27.0 | 32.202091 | 270.218766 | 1451.772072 | 335 | 28662 | 40608 |
| 122 | POLYGON ((-119.43343 37.31364, -119.43343 37.3... | 3.254313 | 2020-10-03T00:00:00 | 6280 | 19.916462 | 28.0 | 36.112503 | 274.300699 | 1461.805801 | 313 | 29114 | 40609 |
| 123 | POLYGON ((-119.43343 37.31365, -119.43343 37.3... | 19.402735 | 2020-10-03T12:00:00 | 6280 | 20.002112 | 28.5 | 34.356263 | 275.740728 | 1467.245064 | 234 | 29348 | 40610 |
| 124 | POLYGON ((-119.43343 37.31365, -119.43343 37.3... | 2.941368 | 2020-10-04T00:00:00 | 6280 | 20.107355 | 29.0 | 36.152268 | 277.331754 | 1475.927568 | 329 | 29677 | 40611 |
125 rows × 12 columns
df = df.set_crs("EPSG:4326")
df.t = df.t.astype("str")
df.explore()Visualize Most Recent Fire Perimeters with Firelines
If we wanted to combine collections to make more informative analyses, we can use some of the same principles.
fline_q = w.collection_queryables('public.eis_fire_fireline')
fline_cols = fline_q['properties']
fline_cols{'wkb_geometry': {'$ref': 'https://geojson.org/schema/Geometry.json'},
'ogc_fid': {'name': 'ogc_fid', 'type': 'number'},
'fid': {'name': 'fid', 'type': 'number'},
't': {'name': 't', 'type': 'string'}}
## Get most recent fire perimeters
most_recent_time = max(*perm['extent']['temporal']['interval'])
print("Most Recent Time =", most_recent_time)
perm_results = w.collection_items(
'public.eis_fire_perimeter',
datetime = most_recent_time,
limit=1000,
filter="farea>5"
)
## Get the most recent fire lines
perimeters = gpd.GeoDataFrame.from_features(perm_results['features'])
perimeter_ids = perimeters.fid.unique()
perimeter_ids = ",".join(map(str, perimeter_ids))
fline_results = w.collection_items(
'public.eis_fire_fireline',
datetime = most_recent_time,
limit=1000,
filter = "fid IN (" + perimeter_ids + ")" # only the fires from the fire perimeter query
)
fline = gpd.GeoDataFrame.from_features(fline_results['features'])Most Recent Time = 2020-10-31T12:00:00+00:00
## Visualize together
perimeters.t = perimeters.t.astype("str")
perimeters = perimeters.set_crs("epsg:4326")
fline.t = fline.t.astype("str")
fline = fline.set_crs("epsg:4326")
m = perimeters.explore()
m = fline.explore(m = m, color = "orange")
m